interface Expression {
    interpret(context: string): boolean;
}

class TerminalExpression implements Expression {
    private data: string;
    public constructor(data: string) {
        this.data = data;
    }
    public interpret(context: string): boolean {
        return context.includes(this.data);
    }
}

class AndExpression implements Expression {
    private left: Expression;
    private right: Expression;
    public constructor(left: Expression, right: Expression) {
        this.left = left;
        this.right = right;
    }
    public interpret(context: string): boolean {
        return this.left.interpret(context) && this.right.interpret(context);
    }
}

class OrExpression implements Expression {
    private left: Expression;
    private right: Expression;
    public constructor(left: Expression, right: Expression) {
        this.left = left;
        this.right = right;
    }
    public interpret(context: string): boolean {
        return this.left.interpret(context) || this.right.interpret(context);
    }
}

function getMaleExpression(): Expression {
    const john: Expression = new TerminalExpression("John");
    const jack: Expression = new TerminalExpression("Jack");
    return new OrExpression(john, jack);
}

function getMarriedWomanExpression(): Expression {
    const jane: Expression = new TerminalExpression("Jane");
    const married: Expression = new TerminalExpression("Married");
    return new AndExpression(jane, married);
}

function main() {
    const isMale: Expression = getMaleExpression();
    const isMarriedWoman: Expression = getMarriedWomanExpression();
    console.log('John is male? ' + isMale.interpret('John'));
    console.log('Jane is married? ' + isMarriedWoman.interpret('Jane Married'));
}

main();
